import threading
import time
import socket
import requests
import json
from typing import Dict, Any, Optional, Union
from .simpleapi import SimpleApi


class SimpleApiClient:
    """SimpleAPI测试客户端，用于单元测试"""
    
    def __init__(self, app: SimpleApi, host: str = "127.0.0.1", port: Optional[int] = None):
        """
        初始化测试客户端
        
        Args:
            app: SimpleApi应用实例
            host: 服务器主机地址
            port: 服务器端口，如果为None则自动分配可用端口
        """
        self.app = app
        self.host = host
        self.port = port or self._find_free_port()
        self.base_url = f"http://{self.host}:{self.port}"
        self.server_thread = None
        self._running = False
    
    def _find_free_port(self) -> int:
        """查找可用的端口"""
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind(('', 0))
            s.listen(1)
            port = s.getsockname()[1]
        return port
    
    def start(self, timeout: float = 5.0) -> None:
        """
        启动测试服务器
        
        Args:
            timeout: 等待服务器启动的超时时间（秒）
        """
        if self._running:
            return
        
        # 在后台线程中启动服务器
        self.server_thread = threading.Thread(
            target=self._run_server,
            daemon=True
        )
        self.server_thread.start()
        
        # 等待服务器启动
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                response = requests.get(f"{self.base_url}/health", timeout=1)
                if response.status_code == 404:  # 服务器已启动，但路由不存在
                    self._running = True
                    return
            except requests.exceptions.RequestException:
                time.sleep(0.1)
                continue
        
        # 如果没有健康检查端点，尝试连接端口
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                    s.settimeout(1)
                    result = s.connect_ex((self.host, self.port))
                    if result == 0:
                        self._running = True
                        time.sleep(0.5)  # 给服务器一点时间完全启动
                        return
            except Exception:
                pass
            time.sleep(0.1)
        
        raise RuntimeError(f"Failed to start server on {self.host}:{self.port} within {timeout} seconds")
    
    def _run_server(self) -> None:
        """在后台运行服务器"""
        try:
            self.app.run(host=self.host, port=self.port)
        except Exception as e:
            print(f"Server error: {e}")
    
    def stop(self) -> None:
        """停止测试服务器"""
        self._running = False
        # 注意：Robyn服务器可能需要特殊的停止方法
        # 这里我们依赖daemon线程在主程序结束时自动结束
    
    def get(self, path: str, **kwargs) -> requests.Response:
        """
        发送GET请求
        
        Args:
            path: 请求路径
            **kwargs: 传递给requests.get的额外参数
            
        Returns:
            requests.Response对象
        """
        if not self._running:
            raise RuntimeError("Server is not running. Call start() first.")
        
        url = f"{self.base_url}{path}"
        return requests.get(url, **kwargs)
    
    def post(self, path: str, data: Any = None, json_data: Dict = None, **kwargs) -> requests.Response:
        """
        发送POST请求
        
        Args:
            path: 请求路径
            data: 请求数据
            json_data: JSON数据（会自动设置Content-Type）
            **kwargs: 传递给requests.post的额外参数
            
        Returns:
            requests.Response对象
        """
        if not self._running:
            raise RuntimeError("Server is not running. Call start() first.")
        
        url = f"{self.base_url}{path}"
        if json_data is not None:
            kwargs['json'] = json_data
        elif data is not None:
            kwargs['data'] = data
        
        return requests.post(url, **kwargs)
    
    def put(self, path: str, data: Any = None, json_data: Dict = None, **kwargs) -> requests.Response:
        """
        发送PUT请求
        
        Args:
            path: 请求路径
            data: 请求数据
            json_data: JSON数据（会自动设置Content-Type）
            **kwargs: 传递给requests.put的额外参数
            
        Returns:
            requests.Response对象
        """
        if not self._running:
            raise RuntimeError("Server is not running. Call start() first.")
        
        url = f"{self.base_url}{path}"
        if json_data is not None:
            kwargs['json'] = json_data
        elif data is not None:
            kwargs['data'] = data
        
        return requests.put(url, **kwargs)
    
    def delete(self, path: str, **kwargs) -> requests.Response:
        """
        发送DELETE请求
        
        Args:
            path: 请求路径
            **kwargs: 传递给requests.delete的额外参数
            
        Returns:
            requests.Response对象
        """
        if not self._running:
            raise RuntimeError("Server is not running. Call start() first.")
        
        url = f"{self.base_url}{path}"
        return requests.delete(url, **kwargs)
    
    def get_json(self, path: str, **kwargs) -> Dict[str, Any]:
        """
        发送GET请求并返回JSON响应
        
        Args:
            path: 请求路径
            **kwargs: 传递给requests.get的额外参数
            
        Returns:
            解析后的JSON数据
        """
        response = self.get(path, **kwargs)
        response.raise_for_status()
        return response.json()
    
    def post_json(self, path: str, data: Any = None, json_data: Dict = None, **kwargs) -> Dict[str, Any]:
        """
        发送POST请求并返回JSON响应
        
        Args:
            path: 请求路径
            data: 请求数据
            json_data: JSON数据
            **kwargs: 传递给requests.post的额外参数
            
        Returns:
            解析后的JSON数据
        """
        response = self.post(path, data=data, json_data=json_data, **kwargs)
        response.raise_for_status()
        return response.json()
    
    def __enter__(self):
        """上下文管理器入口"""
        self.start()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        self.stop()
    
    @property
    def is_running(self) -> bool:
        """检查服务器是否正在运行"""
        return self._running


# 便捷函数
def create_test_client(app: SimpleApi, **kwargs) -> SimpleApiClient:
    """
    创建测试客户端的便捷函数
    
    Args:
        app: SimpleApi应用实例
        **kwargs: 传递给SimpleApiClient的额外参数
        
    Returns:
        SimpleApiClient实例
    """
    return SimpleApiClient(app, **kwargs)
